using System.Linq;
using System.Web.Security;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System;
using System.Security.Cryptography;
using System.Text;
using BLToolkit.Data.Linq;
using Calendar.Logic.ObjectManager;
using Calendar.Logic.ObjectManager.Authorization;
using Calendar.Logic.ObjectModel.Authorization;

/* CONVERTED TO PostgreSQL on 9-14-2006 by Lee@woodchop.com - http://blog.woodchop.com
 * BASED ON THE ORIGINAL MySQL IMPLEMENTATION BY Andri (see original comments below)
 */

/* 
-- Please, send me an email (andriniaina@gmail.com) if you have done some improvements or bug corrections to this file
      or leave your modifications on the comments page on sprinj.com
	  
*/


namespace Calendar.Logic.Core
{
    public sealed class PostgreSqlMembershipProvider : MembershipProvider
    {

        //
        // Global connection string, generated password length, generic exception message, event log info.
        //

        private const int newPasswordLength = 5;

        private byte[] encryptionKey;// = new byte[] { 255, 30, 40, 20, 13, 59 };


        //
        // System.Configuration.Provider.ProviderBase.Initialize Method
        //
        public override void Initialize(string name, NameValueCollection config)
        {
            //
            // Initialize values from web.config.
            //

            if (config == null)
                throw new ArgumentNullException("config");

            if (name == null || name.Length == 0)
                name = "PostgreSqlMembershipProvider";

            if (String.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "PostgreSql Membership provider");
            }

            // Initialize the abstract base class.
            base.Initialize(name, config);

            pApplicationName = GetConfigValue(config["applicationName"], System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
            pMaxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
            pPasswordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
            pMinRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
            pMinRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
            pPasswordStrengthRegularExpression = Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], ""));
            pEnablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
            pEnablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "true"));
            pRequiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
            pRequiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "true"));

            //GlobalContext.Instance.ApplicationName = pApplicationName;

            try
            {
                encryptionKey = HexToByte(GetConfigValue(config["encryptionKey"], "ABCDEEA2EFAA00B42A"));
            }
            catch (Exception)
            { }

            string temp_format = config["passwordFormat"];
            if (temp_format == null)
            {
                temp_format = "Hashed";
            }

            switch (temp_format)
            {
                case "Hashed":
                    pPasswordFormat = MembershipPasswordFormat.Hashed;
                    break;
                case "Encrypted":
                    pPasswordFormat = MembershipPasswordFormat.Encrypted;
                    break;
                case "Clear":
                    pPasswordFormat = MembershipPasswordFormat.Clear;
                    break;
                default:
                    throw new ProviderException("Password format not supported.");
            }
        }

        //
        // A helper function to retrieve config values from the configuration file.
        //
        private string GetConfigValue(string configValue, string defaultValue)
        {
            return String.IsNullOrEmpty(configValue) ? defaultValue : configValue;
        }


        //
        // System.Web.Security.MembershipProvider properties.
        //
        private string pApplicationName;
        public override string ApplicationName
        {
            get { return pApplicationName; }
            set { pApplicationName = value; }
        }

        private bool pEnablePasswordReset;
        public override bool EnablePasswordReset
        {
            get { return pEnablePasswordReset; }
        }


        private bool pEnablePasswordRetrieval;
        public override bool EnablePasswordRetrieval
        {
            get { return pEnablePasswordRetrieval; }
        }

        private bool pRequiresQuestionAndAnswer;
        public override bool RequiresQuestionAndAnswer
        {
            get { return pRequiresQuestionAndAnswer; }
        }


        private bool pRequiresUniqueEmail;
        public override bool RequiresUniqueEmail
        {
            get { return pRequiresUniqueEmail; }
        }

        private int pMaxInvalidPasswordAttempts;
        public override int MaxInvalidPasswordAttempts
        {
            get { return pMaxInvalidPasswordAttempts; }
        }

        private int pPasswordAttemptWindow;
        public override int PasswordAttemptWindow
        {
            get { return pPasswordAttemptWindow; }
        }

        private MembershipPasswordFormat pPasswordFormat;
        public override MembershipPasswordFormat PasswordFormat
        {
            get { return pPasswordFormat; }
        }

        private int pMinRequiredNonAlphanumericCharacters;
        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return pMinRequiredNonAlphanumericCharacters; }
        }

        private int pMinRequiredPasswordLength;
        public override int MinRequiredPasswordLength
        {
            get { return pMinRequiredPasswordLength; }
        }

        private string pPasswordStrengthRegularExpression;
        public override string PasswordStrengthRegularExpression
        {
            get { return pPasswordStrengthRegularExpression; }
        }

        //
        // System.Web.Security.MembershipProvider methods.
        //

        public override bool ChangePassword(string username, string oldPwd, string newPwd)
        {
            if (!ValidateUser(username, oldPwd))
                return false;

            ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPwd, true);
            OnValidatingPassword(args);

            if (args.Cancel)
                if (args.FailureInformation != null)
                    throw args.FailureInformation;
                else
                    throw new MembershipPasswordException("New password is not valid.");

            try
            {
                string pwSalt;
                bool isLockedOut;
                var dbAnswer = getPasswordAnswer(username, out isLockedOut, out pwSalt);

                var r = UserManager.Table.SelectByName(username).
                    Set(u => u.Password, encodePassword(newPwd, pwSalt)).
                    Set(u => u.PasswordSalt, pwSalt).
                    Set(u => u.PasswordAnswer, encodePassword(dbAnswer, pwSalt)).
                    Set(u => u.LastPasswordChangedDate, DateTime.Now).
                    Update();

                return (r > 0);
            }
            catch (Exception)
            {
                return false;
            }
        }



        //
        // MembershipProvider.ChangePasswordQuestionAndAnswer
        //

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPwdQuestion, string newPwdAnswer)
        {
            if (!ValidateUser(username, password))
                return false;

            try
            {
                var r = UserManager.Table.SelectByName(username).
                    Set(u => u.PasswordQuestion, newPwdQuestion).
                    Set(u => u.PasswordAnswer, encodePassword(newPwdAnswer, getPasswordSalt(username))).
                    Set(u => u.LastPasswordChangedDate, DateTime.Now).
                    Update();

                return (r > 0);
            }
            catch (Exception)
            {
                return false;
            }
        }

        //
        // MembershipProvider.CreateUser
        //
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            username = username.ToLower(); // ignore case
            ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, password, true);
            OnValidatingPassword(args);

            if (args.Cancel)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }

            if (this.RequiresQuestionAndAnswer)
            {
                if (passwordQuestion == null || passwordQuestion.Length == 0)
                {
                    status = MembershipCreateStatus.InvalidQuestion;
                    return null;
                }
                else if (passwordAnswer == null || passwordAnswer.Length == 0)
                {
                    status = MembershipCreateStatus.InvalidQuestion;
                    return null;
                }
            }
            string name = GetUserNameByEmail(email);
            if (RequiresUniqueEmail && !string.IsNullOrWhiteSpace(name))
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return null;
            }

            if (null == GetUser(username, false))
            {
                var createDate = DateTime.Now;

                try
                {
                    var user = UserManager.Instance.CreateInstance();
                    var salt = getPasswordSalt();

                    user.Username = username;
                    user.Name = username;
                    user.Password = encodePassword(password, salt);
                    user.PasswordSalt = salt;
                    user.Email = email;
                    user.PasswordQuestion = passwordQuestion;
                    user.PasswordAnswer = passwordAnswer == null ? null : encodePassword(passwordAnswer, salt);
                    user.IsApproved = isApproved;
                    user.Comment = "";
                    user.CreationDate = createDate;
                    user.LastPasswordChangedDate = createDate;
                    user.LastActivityDate = createDate;
                    user.ApplicationName = pApplicationName;
                    user.IsLockedOut = false;
                    user.LastLockedOutDate = createDate;
                    user.FailedPasswordAttemptCount = 0;
                    user.FailedPasswordAttemptWindowStart = createDate;
                    user.FailedPasswordAnswerAttemptCount = 0;
                    user.FailedPasswordAnswerAttemptWindowStart = createDate;

                    var id = UserManager.Instance.Insert(user);
                    status = (id > 0) ? MembershipCreateStatus.Success : MembershipCreateStatus.UserRejected;

                    return GetUser(username, false);
                }
                catch (Exception)
                {
                    status = MembershipCreateStatus.UserRejected;
                }
            }
            else
            {
                status = MembershipCreateStatus.DuplicateUserName;
            }

            return null;
        }



        //
        // MembershipProvider.DeleteUser
        //
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            try
            {
                return (UserManager.Table.SelectByName(username).Delete() > 0);
            }
            catch (Exception)
            {
                return false;
            }
        }



        //
        // MembershipProvider.GetAllUsers
        //

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            var users = new MembershipUserCollection();

            try
            {
                foreach (var user in UserManager.Table)
                {
                    users.Add(GetUserFromReader(user));
                }
            }
            finally
            {
                totalRecords = users.Count;
            }

            return users;
        }

        //
        // MembershipProvider.GetNumberOfUsersOnline
        //
        public override int GetNumberOfUsersOnline()
        {
            TimeSpan onlineSpan = new TimeSpan(0, System.Web.Security.Membership.UserIsOnlineTimeWindow, 0);
            DateTime compareTime = DateTime.Now.Subtract(onlineSpan);

            try
            {
                return UserManager.Table.SelectInOnline(compareTime).Count();
            }
            catch (Exception)
            {
                return 0;
            }
        }


        //
        // MembershipProvider.GetPassword
        //
        public override string GetPassword(string username, string answer)
        {
            if (!EnablePasswordRetrieval)
            {
                throw new ProviderException("Password Retrieval Not Enabled.");
            }

            if (PasswordFormat == MembershipPasswordFormat.Hashed)
            {
                throw new ProviderException("Cannot retrieve Hashed passwords.");
            }

            string password = "";
            string dbAnswer = "";

            
            try
            {
                var user = UserManager.Table.SelectByName(username).FirstOrDefault();
                if (user.IsLockedOut)
                {
                    throw new MembershipPasswordException("The supplied user is locked out.");
                }

                password = user.Password;
                dbAnswer = user.PasswordAnswer;
            }
            catch(Exception)
            {
                throw new MembershipPasswordException("The supplied user name is not found.");
            }

            if (RequiresQuestionAndAnswer && !validatePassword(answer, dbAnswer, getPasswordSalt(username)))
            {
                UpdateFailureCount(username, "passwordAnswer");

                throw new MembershipPasswordException("Incorrect password answer.");
            }


            if (PasswordFormat == MembershipPasswordFormat.Encrypted)
            {
                password = UnEncodePassword(password);
            }

            return password;
        }

        //
        // MembershipProvider.GetUser(string, bool)
        //
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            username = username.ToLower(); // ignore case
            MembershipUser u = null;

            try
            {
                var user = UserManager.Table.SelectByName(username).FirstOrDefault();
                if (user != null)
                {
                    u = GetUserFromReader(user);

                    if (userIsOnline)
                    {
                        UserManager.Table.SelectByName(username).Set(us => us.LastActivityDate, DateTime.Now).Update();
                    }
                }
            }
            catch (Exception)
            {
            }

            return u;
        }


        //
        // MembershipProvider.GetUser(object, bool)
        //
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            MembershipUser u = null;

            try
            {
                var user = UserManager.Table.Select((int)providerUserKey).FirstOrDefault();
                if (user != null)
                {
                    u = GetUserFromReader(user);

                    if (userIsOnline)
                    {
                        UserManager.Table.Select((int)providerUserKey).Set(us => us.LastActivityDate, DateTime.Now).Update();
                    }
                }
            }
            catch (Exception)
            {
            }

            return u;
        }


        //
        // GetUserFromReader
        //    A helper function that takes the current row from the NpgsqlDataReader
        //    and hydrates a MembershiUser from the values. Called by the 
        //    MembershipUser.GetUser implementation.
        //
        private MembershipUser GetUserFromReader(User user)
        {
            return new MembershipUser(
                this.Name,
                user.Username,
                user.ID,
                user.Email,
                user.PasswordQuestion,
                user.Comment,
                user.IsApproved,
                user.IsLockedOut,
                user.CreationDate,
                user.LastLoginDate,
                user.LastActivityDate,
                user.LastPasswordChangedDate,
                user.LastLockedOutDate
            );
        }


        //
        // MembershipProvider.UnlockUser
        //

        public override bool UnlockUser(string username)
        {
            try
            {
                var r = UserManager.Table.SelectByName(username).
                    Set(u => u.IsLockedOut, false).
                    Set(u => u.LastLockedOutDate, DateTime.Now).
                    Update();
                return (r > 0);
            }
            catch (Exception)
            {

            }

            return false;
        }


        //
        // MembershipProvider.GetUserNameByEmail
        //
        public override string GetUserNameByEmail(string email)
        {
            try
            {
                var user = UserManager.Table.SelectByEmail(email).FirstOrDefault();
                return user != null ? user.Username : string.Empty;
            }
            catch(Exception)
            {
                return string.Empty;
            }
        }

        //
        // MembershipProvider.ResetPassword
        //
        public override string ResetPassword(string username, string answer)
        {
            if (!EnablePasswordReset)
            {
                throw new NotSupportedException("Password reset is not enabled.");
            }

            if (RequiresQuestionAndAnswer && (answer == null || answer.Length == 0))
            {
                UpdateFailureCount(username, "passwordAnswer");

                throw new ProviderException("Password answer required for password reset.");
            }

            string newPassword = System.Web.Security.Membership.GeneratePassword(newPasswordLength, MinRequiredNonAlphanumericCharacters);

            ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true);
            OnValidatingPassword(args);

            if (args.Cancel)
                if (args.FailureInformation != null)
                    throw args.FailureInformation;
                else
                    throw new MembershipPasswordException("Reset password canceled due to password validation failure.");


            bool isLockedOut;
            string salt;
            string dbAnswer = getPasswordAnswer(username, out isLockedOut, out salt);

            if (isLockedOut)
                throw new MembershipPasswordException("The user is locked out.");

            if (RequiresQuestionAndAnswer && !validatePassword(answer, dbAnswer, salt))
            {
                UpdateFailureCount(username, "passwordAnswer");

                throw new MembershipPasswordException("Incorrect answer.");
            }

            try
            {
                var r = UserManager.Table.SelectByName(username).
                    Set(u => u.Password, encodePassword(newPassword, salt)).
                    Set(u => u.PasswordSalt, salt).
                    Set(u => u.PasswordAnswer, encodePassword(dbAnswer, salt)).
                    Set(u => u.LastPasswordChangedDate, DateTime.Now).
                    Update();

                if (r > 0)
                {
                    return newPassword;
                }
            }
            catch (Exception)
            {

            }

            throw new MembershipPasswordException("User not found, or user is locked out. Password not Reset.");
        }

        private string getPasswordAnswer(string username, out bool isLockedOut, out string salt)
        {
            try
            {
                var user = UserManager.Table.SelectByName(username).FirstOrDefault();
                if (user != null)
                {
                    salt = user.PasswordSalt;
                    isLockedOut = user.IsLockedOut;

                    return user.PasswordAnswer;
                }
            }
            catch (Exception)
            {

            }

            throw new MembershipPasswordException("The supplied user name is not found.");
        }

        //
        // MembershipProvider.UpdateUser
        //
        public override void UpdateUser(MembershipUser mUser)
        {
            try
            {
                UserManager.Table.SelectByName(mUser.UserName).
                    Set(u => u.Email, mUser.Email).
                    Set(u => u.Comment, mUser.Comment).
                    Set(u => u.IsApproved, mUser.IsApproved).
                    Update();
            }
            catch (Exception)
            {

            }
        }


        //
        // MembershipProvider.ValidateUser
        //

        public override bool ValidateUser(string username, string password)
        {
            var isValid = false;

            username = username.ToLower(); // ignore case

            try
            {
                var user = UserManager.Table.SelectByName(username).Where(u => u.IsLockedOut == false).FirstOrDefault();
                if (user != null)
                {
                    if (validatePassword(password, user.Password, user.PasswordSalt))
                    {
                        if (user.IsApproved)
                        {
                            isValid = true;

                            UserManager.Table.SelectByName(username).
                                Set(u => u.LastLoginDate, DateTime.Now).
                                Set(u => u.LastActivityDate, DateTime.Now).
                                Update();
                        }
                    }
                    else
                    {
                        UpdateFailureCount(username, "password");
                    }
                }
            }
            catch (Exception)
            {
            }

            return isValid;
        }


        //
        // UpdateFailureCount
        //   A helper method that performs the checks and updates associated with
        // password failure tracking.
        //
        private void UpdateFailureCount(string username, string failureType)
        {
            try
            {
                var user = UserManager.Table.SelectByName(username).FirstOrDefault();
                if (user != null)
                {
                    var windowStart = new DateTime();
                    var failureCount = 0;


                    switch (failureType)
                    {
                        case "password":
                            failureCount = user.FailedPasswordAttemptCount;
                            windowStart = user.FailedPasswordAttemptWindowStart;
                            break;
                        case "passwordAnswer":
                            failureCount = user.FailedPasswordAnswerAttemptCount;
                            windowStart = user.FailedPasswordAnswerAttemptWindowStart;
                            break;
                    }


                    var windowEnd = windowStart.AddMinutes(PasswordAttemptWindow);

                    if (failureCount == 0 || DateTime.Now > windowEnd)
                    {
                        // First password failure or outside of PasswordAttemptWindow. 
                        // Start a new password failure count from 1 and a new window starting now.

                        var r = 0;
                        switch (failureType)
                        {
                            case "password":
                                r = UserManager.Table.SelectByName(username).
                                    Set(u => u.FailedPasswordAttemptCount, 1).
                                    Set(u => u.FailedPasswordAttemptWindowStart, DateTime.Now).
                                    Update();
                                break;
                            case "passwordAnswer":
                                r = UserManager.Table.SelectByName(username).
                                    Set(u => u.FailedPasswordAnswerAttemptCount, 1).
                                    Set(u => u.FailedPasswordAnswerAttemptWindowStart, DateTime.Now).
                                    Update();
                                break;
                        }

                        if (r <= 0)
                            throw new ProviderException("Unable to update failure count and window start.");
                    }
                    else if (failureCount++ >= MaxInvalidPasswordAttempts)
                    {
                        // Password attempts have exceeded the failure threshold. Lock out
                        // the user.

                        var r = UserManager.Table.SelectByName(username).
                            Set(u => u.IsLockedOut, true).
                            Set(u => u.LastLockedOutDate, DateTime.Now).
                            Update();

                        if (r <= 0)
                            throw new ProviderException("Unable to lock out user.");
                    }
                    else
                    {
                        // Password attempts have not exceeded the failure threshold. Update
                        // the failure counts. Leave the window the same.

                        var r = 0;
                        switch (failureType)
                        {
                            case "password":
                                r = UserManager.Table.SelectByName(username).Set(u => u.FailedPasswordAttemptCount, failureCount).Update();
                                break;
                            case "passwordAnswer":
                                r = UserManager.Table.SelectByName(username).Set(u => u.FailedPasswordAnswerAttemptCount, failureCount).Update();
                                break;
                        }

                        if (r <= 0)
                            throw new ProviderException("Unable to lock out user.");
                    }
                }
            }
            catch(Exception)
            {  
            }
        }



        //
        // CheckPassword
        //   Compares password values based on the MembershipPasswordFormat.
        //
        private bool validatePassword(string password, string dbpassword, string salt)
        {
            switch (PasswordFormat)
            {
                case MembershipPasswordFormat.Encrypted:
                    return password == UnEncodePassword(dbpassword);
                case MembershipPasswordFormat.Hashed:
                    return dbpassword == encodePassword(password, salt);
                default:
                    return false;
            }
        }


        //
        // EncodePassword
        //   Encrypts, Hashes, or leaves the password clear based on the PasswordFormat.
        //
        private static SHA1 hash = null;
        private string encodePassword(string password, string salt)
        {
            if (password == null)
                return null;
            if (salt == null || salt.Length == 0)
                return password;

            switch (PasswordFormat)
            {
                case MembershipPasswordFormat.Clear:
                    return password;
                case MembershipPasswordFormat.Encrypted:
                    return Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
                case MembershipPasswordFormat.Hashed:
                    if (hash == null)
                        hash = SHA1Managed.Create();
                    return Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password + salt)));
                default:
                    throw new ProviderException("Unsupported password format.");
            }
        }

        private string getPasswordSalt()
        {
            return Membership.GeneratePassword(24, 12);
        }

        private string getPasswordSalt(string username)
        {
            try
            {
                return UserManager.Table.SelectByName(username).Select(u => u.PasswordSalt).FirstOrDefault() ?? string.Empty;
            }
            catch (Exception)
            {
            }

            return string.Empty;
        }


        //
        // UnEncodePassword
        //   Decrypts or leaves the password clear based on the PasswordFormat.
        //
        private string UnEncodePassword(string encodedPassword)
        {
            switch (PasswordFormat)
            {
                case MembershipPasswordFormat.Clear:
                    return encodedPassword;
                case MembershipPasswordFormat.Encrypted:
                    return Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(encodedPassword)));
                case MembershipPasswordFormat.Hashed:
                    throw new ProviderException("Cannot unencode a hashed password.");
                default:
                    throw new ProviderException("Unsupported password format.");
            }
        }


        //
        // MembershipProvider.FindUsersByName
        //
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            var users = new MembershipUserCollection();
            var startIndex = pageSize * pageIndex;

            try
            {
                foreach (var user in UserManager.Table.SelectByNameToMatch(usernameToMatch)) users.Add(GetUserFromReader(user));
            }
            finally
            {
                totalRecords = users.Count;
            }

            return users;
        }

        //
        // MembershipProvider.FindUsersByEmail
        //

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            var users = new MembershipUserCollection();
            var startIndex = pageSize * pageIndex;

            try
            {
                foreach (var user in UserManager.Table.SelectByEmailToMatch(emailToMatch)) users.Add(GetUserFromReader(user));
            }
            finally
            {
                totalRecords = users.Count;
            }

            return users;
        }

        private byte[] HexToByte(string hexString)
        {
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            return returnBytes;
        }
    }
}